<?php

namespace tmcore\services;

use app\common\enum\FileEnum;
use app\common\model\file\File;
use tmcore\exceptions\UploadException;
use tmcore\services\upload\Upload;
use tmcore\traits\ErrorTrait;
use tmcore\traits\TransTrait;
use Exception;

class UploadService
{
    use ErrorTrait;

    use TransTrait;

    protected $uploadDriver;

    protected $uploadConfig;

    protected Upload $uploadService;

    public function __construct($driver = '')
    {
        $configService = (new ConfigService());

        // 获取默认驱动
        $this->uploadDriver = $driver?:$configService->getConfig('default','upload');

        // 获取上传配置
        $this->uploadConfig = $configService->getConfig('upload','sys');

        // 实例化上传类
        $this->uploadService = (new Upload($this->uploadDriver));
    }

    /**
     *  公共上传
     * @param string $type 类型  image-图片 file-文件 audio-音频 video-视频
     * @param array $params 上传参数 file-文件对象名称 name-文件名称 size-文件大小(kb) ext-扩展后缀 cid-分类id source_id-上传者id multiple-批量上传 save_dir-上传文件目录
     * @param int $source 上传渠道类型
     * @return bool|array
     * @throws Exception
     */
    public function upload($type, $params = [], int $source = FileEnum::SOURCE_ADMIN)
    {
        try {
            // 获取上传参数
            list($file, $name, $size, $ext, $cid, $source_id, $multiple, $saveDir) = [
                isset($params['file'])?$params['file']:'',
                isset($params['name'])?$params['name']:'',
                isset($params['size'])?$params['size']:0,
                isset($params['ext'])?$params['ext']:'',
                isset($params['cid'])?$params['cid']:0,
                isset($params['source_id'])?$params['source_id']:0,
                isset($params['multiple'])?$params['multiple']:false,
                isset($params['save_dir'])?$params['save_dir']:'',
            ];

            $data = [];
            $data['cid'] = $cid;
            $data['file'] = $file;
            $data['file_type'] = $type;
            $data['source'] = $source;
            $data['source_id'] = $source_id;

            $upload_image_size = $this->uploadConfig['upload_image_size'];
            $upload_image_ext = $this->uploadConfig['upload_image_ext'];
            $upload_file_size =$this->uploadConfig['upload_file_size'];
            $upload_file_ext = $this->uploadConfig['upload_file_ext'];

            switch ($type) {
                case 'image':
                    $data['type'] = FileEnum::IMAGE_TYPE;
                    $data['size'] = $size?:$upload_image_size;
                    $data['ext'] = $ext?:$upload_image_ext;
                    $savePath = $saveDir?:"uploads/images/" . date('Ymd');
                    break;

                case 'file':
                    $data['type'] = FileEnum::FILE_TYPE;
                    $data['size'] = $size?:$upload_file_size;
                    $data['ext'] = $ext?:$upload_file_ext;
                    $savePath = $saveDir?:"uploads/files/" . date('Ymd');
                    break;

                case 'audio':
                    $data['type'] = FileEnum::AUDIO_TYPE;
                    $data['size'] = $size?:$upload_file_size;
                    $data['ext'] = $ext?:$upload_file_ext;
                    $savePath = $saveDir?:"uploads/audios/" . date('Ymd');
                    break;

                case 'video':
                    $data['type'] = FileEnum::VIDEO_TYPE;
                    $data['size'] = $size?:$upload_file_size;
                    $data['ext'] = $ext?:$upload_file_ext;
                    $savePath = $saveDir?:"uploads/videos/" . date('Ymd');
                    break;

                default:
                    return self::setError('上传文件类型不对');
                    break;
            }

            // 设置文件信息
            $this->uploadService->setSaveInfo($savePath, $name?:'');

            // 检验是否多文件上传
            if(!$multiple){
                return $this->uploadFile($data);
            } else {
                return $this->uploadFileMultiple($data);
            }
        } catch (Exception $e) {
            throw new UploadException($e->getMessage());
        }
    }

    /**
     * 单文件上传
     * @param $params
     * @return array
     * @throws Exception
     */
    protected function uploadFile($params)
    {
        // 验证规则
        $rule = [];
        if($params['size'])$rule['fileSize'] = $params['size'];
        if($params['ext'])$rule['fileExt'] = $params['ext'];

        $res = $this->uploadService->upload($params['file'], $rule, $params['file_type']);
        if($res) {
            $file = File::create([
                'cid'         => $params['cid'],
                'type'        => $params['type'],
                'name'        => $res['fileName'],
                'real_name'   => $res['originalName'],
                'uri'         => $res['url'],
                'size'        => round($res['size']/1024),
                'ext'         => $res['ext'],
                'upload_type' => $res['upload_type'],
                'md5'         => $res['md5'],
                'source'      => $params['source'],
                'source_id'   => $params['source_id']
            ]);
            if(empty($file['id'])) {
                throw new UploadException('新增文件记录失败');
            } else {
                return [
                    'id'   => $file['id'],
                    'cid'  => $file['cid'],
                    'type' => $file['type'],
                    'name' => $file['name'],
                    'uri'  => get_file_url($file['uri']),
                    'url'  => $file['uri']
                ];
            }
        }
    }

    /**
     * 多文件上传
     * @param $params
     * @return array
     * @throws Exception
     */
    protected function uploadFileMultiple($params)
    {
        // 验证规则
        $rule = [];
        if($params['size'])$rule['fileSize'] = $params['size'];
        if($params['ext'])$rule['fileExt'] = $params['ext'];

        $files = $this->uploadService->batchUpload($params['file'], $rule, $params['file_type']);

        if($files) {
            if(!is_array($files) || !$files) {
                throw new UploadException('上传文件信息有误');
            }

            $data = [];
            self::beginTrans();
            try {
                foreach($files as $file){
                    $res = File::create([
                        'cid'         => $params['cid'],
                        'type'        => $params['type'],
                        'name'        => $file['fileName'],
                        'real_name'   => $file['originalName'],
                        'uri'         => $file['url'],
                        'size'        => round($file['size']/1024),
                        'upload_type' => $file['upload_type'],
                        'md5'         => $file['md5'],
                        'ext'         => $file['ext'],
                        'source'      => $params['source'],
                        'source_id'   => $params['source_id']
                    ]);

                    if(empty($res['id'])) {
                        throw new UploadException('新增文件记录失败');
                    } else {
                        array_unshift($data, [
                            'id'   => $file['id'],
                            'cid'  => $file['cid'],
                            'type' => $file['type'],
                            'name' => $file['name'],
                            'uri'  => get_file_url($file['uri']),
                            'url'  => $file['uri']
                        ]);
                    }
                }
                self::commitTrans();
                return $data;
            } catch (Exception $e) {
                self::rollbackTrans();
                throw new UploadException($e->getMessage());
            }
        }
    }

}